#include "matrix.h"
#include "terminal.h"
#include "console.h"
#include "thread.h"
#include "mutex.h"

/**
 * test the basic functionality of mutex
 */

static mx_mutex_t mutex;

static mx_thread_t thread1;
static mx_uint8_t thread1_stack[8192];
static mx_int32_t thread1_entry (mx_void_pt param)
{
    consoleline("this is thread 1");
    mx_mutex_enter(&mutex);
    consoleline("thread1, get the mutex");
    mx_thread_sleep(3000);
    consoleline("thread1, release mutex");
    mx_mutex_leave(&mutex);
    return 0;
}

static mx_thread_t thread2;
static mx_uint8_t thread2_stack[8192];
static mx_int32_t thread2_entry (mx_void_pt param)
{
    consoleline("this is thread 2");
    mx_mutex_enter(&mutex);
    consoleline("thread2, get the mutex");
    mx_thread_sleep(3000);
    consoleline("thread2, release mutex");
    mx_mutex_leave(&mutex);
    return 0;
}

static mx_thread_t thread3;
static mx_uint8_t thread3_stack[8192];
static mx_int32_t thread3_entry (mx_void_pt param)
{
    consoleline("this is thread 3");
    mx_mutex_enter(&mutex);
    consoleline("thread3, get the mutex");
    mx_thread_sleep(3000);
    consoleline("thread3, release mutex");
    mx_mutex_leave(&mutex);
    return 0;
}

mx_size_t mutextest_entry (mx_usize_t argc, char** argv)
{
    mx_mutex_init(&mutex);

    mx_thread_mount(&thread1, "thread1", 200, MX_DEFAULT_TICK,
                    thread1_stack, len(mx_uint8_t, thread1_stack), thread1_entry, mx_null);
    mx_thread_start(&thread1);

    mx_thread_mount(&thread2, "thread2", 200, MX_DEFAULT_TICK,
                    thread2_stack, len(mx_uint8_t, thread2_stack), thread2_entry, mx_null);
    mx_thread_start(&thread2);
    
    mx_thread_mount(&thread3, "thread3", 200, MX_DEFAULT_TICK,
                    thread3_stack, len(mx_uint8_t, thread3_stack), thread3_entry, mx_null);
    mx_thread_start(&thread3);
}
MX_TERMINAL_EXPORT("mutextest", mutextest_entry);

/* 输出结果：
    this is thread 3
    thread3, get the mutex
    this is thread 2
    this is thread 1
:delay 3s
    thread3, release mutex
    thread2, get the mutex
:delay 3s
    thread2, release mutex
    thread1, get the mutex
:delay 3s
    thread1, release mutex
 */
